<?php
/**
 * 新生支付
 * Date: 2019年4月18日
 * Time: 上午10:21:51
 */
namespace app\common\service\PayService\HnaPay;

use app\Normal;
use app\common\service\RequestService\Http;
use app\common\service\PayService\HnaPay\HnaPayException;
use app\Model\BbcModel\Order;
use app\Model\BbcModel\Host;

class HnPayClient
{
    /**
     * instance
     * @access private
     * @var    array
     */
    private static $instance;

    /**
     * config
     * @access private
     * @var    array
     */
    private $config;

    /**
     * notify url
     * @access private
     * @var    string
     */
    private $notify_url;
    /**
     *
     * @var type
     */
    private $return_url;

    /**
     * 支付对象
     * @access private
     * @var    object
     */
    private $pay;

    /**
     * channel
     * @access public
     * @var    string
     */

    private function __clone(){}

    private function __construct($config){
        $this->config = $config;
    }

    /**
     * @get instance
     * @param    array $config
     * @access   public
     * @return   static
     */
    public static function instance($config = [])
    {
        if (empty($config)) {
            throw new HnaPayException("undefined pay config", 20001);
        }

        $name = md5(serialize($config));

        if (empty(self::$instance[$name])) {
            self::$instance[$name] = new static($config);
        }

        return self::$instance[$name];
    }

    public function pay($param=[])
    {
        $data=[];
        $head=[
            'serCode'=>'101005',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $content=[
            //商户交易订单号
            'merOrderId'=>$param['merOrderId'],
            //商户显示名称
            'displayName'=>$param['displayName'],
            //商品名称
            'goodsName'=>$param['goodsName'],
            //商品数量
            'goodsCount'=>(int)$param['goodsCount'],
            //商品类别
            'goodsType'=>$param['goodsType']??'',//tradeType=0004 货物贸易时必填服装-00 食品-01 电子产 品-02 箱包-03 日用品-04 保健品-05 化妆品-06 家电 -07tradeType=0013 旅游服务时必 填旅游签证-22
            //订单金额
            'orderAmount'=>(int)(round($param['orderAmount']*100,2)),//订单金额。以分为单位。
            'orderCurrencyCode'=>'CNY',//订单币种
            //贸易类型
            'tradeType'=>$param['tradeType']??'0002',//0001-担保交易，0002-即时付 款，0003-跨境支付，0004-货物 贸易，0005-酒店住宿，0006-机 票旅游，0007-留学教育，0008- 国际会展，0009-国际会议， 0010-物流支付，0013-旅游服 务，0014-软件服务，0015-管理咨询，0016-设计咨询 注:境内订单上送 0002，如果是跨 境进口订单，需上送 0004-0016 对 应的贸易类型，否则订单无法用于 后续购付汇。Eg:进口商品上送 0004。
            //支付方式
            'payType'=>(string)$param['payType'],//填写数字代码。1:B2C (B2C 直连到银行) 2:B2B(B2B 直连到银行)3:QUICK_PAY(快捷支付，该接口 为预支付申请) 4:QRCODE(扫码支付，商户被扫) 5:JS (公众号，小程序/服务 窗支付) 6:PAYCODE(刷卡支付，商户主 扫)7:APP(APP 支付) 8:H5 直连 9:预付费卡支付
            //目标机构资金代码
            'orgCode'=>$param['orgCode'],//填写机构英文代码,大写。参见 9.3 机构代码payType=1、2 或 3 时必填，支 持:CMB,ICBC...(具体参见银行 机构代码);payType=4 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信)，UNIONPAY(银联)，QQPAY (QQ 支付),JDPAY(京东支付); payType=5 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信);payType=6 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信);payType=7,8 时必填，支持: ALIPAY(支付宝),WECHATPAY(微 信);payType=9 时必填，支持: HNACARD(新生预付费卡);
            //付款方账户
            'payerAccount'=>$param['payerAccount'],//payType=3 时，必填，为发起快 捷支付的协议帐号。(通过 6.10 接口获取，或者首次支付后将返 回。)payType=5 时，必填。微信为 open_Id, 支付宝为 user_ID。
            'payCurrencyCode'=>'CNY',//交易币种
            'settleCurrencyCode'=>'CNY',//结算币种
            //分账标识
            'shareFlag'=>$param['shareFlag']??'0',//0:不分账 1:分账 2:延时分账
//            //子订单/分账订 单信息
            'subMerchantOrderDetails'=>'',
            'returnUrl'=> $param['returnUrl'],//回调地址
            'noticeUrl'=>$param['noticeUrl'],//通知地址
            'platformId'=>'',//平台交易时填写。由支付系统分 配给平台商户。
            'customerId'=>'',//商户传给新生支付购买用户在 商家的用户名(需要使用快捷支 付时必填，注:使用快捷支付需 要先开通相应的产品权限)
            'customerType'=>$param['customerType']??'',//商户端下单时付款人的类型 1- 个人，2-企业。当tradeType是 0004 至 0016 间任一个必填。
            'customerName'=>$param['customerName']??'',//商户端下单时付款人名称，当 tradeType 是 0004 至 0016 间任 一个必填。
            'customerIdNo'=>$param['customerIdNo']??'',//customerType=1，个人对应身 份证号码。customerType=2 企 业对应组织机构号码。当 tradeType 是 0004 至 0016 间任 一个必填。
            'customerTel'=>$param['customerTel']??'',//当 tradeType 是 0004 至 0016 间 任一个必填。
            'bankCardNo'=>'',//商户用户银行卡 payType=3:QUICK_PAY 时必填
            'bankCardType'=>'',//商户用户银行卡 类型,当 payType=3，且卡 bin 无法识 别时必填。1:借记卡2:贷记卡
            'expireData'=>'',//有效期,BankCardType=2 时必填，格式: MMYY，如:0312
            'cvn'=>'',//BankCardType=2 时必填,如: 888
            'remark'=>'',
            'reserve1'=>'',
            'reserve2'=>$param['reserve2']??''//当微信备案>1 时必填。该字段 为 APPID。

        ];
        $data['head']=$head;
        $data['content']=$content;
        $data['sign']=$this->makeSign($data);
        Order::instance()->edit(['pay_sn'=>$content['merOrderId']],['initalRequest'=>json_encode($data,JSON_UNESCAPED_UNICODE)]);
        return $this->requestHnapay($data);
    }

    public function returnOrder($param)
    {
        $head=[
            'serCode'=>'101006',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }

    public function shareReturnOrder($param)
    {
        $head=[
            'serCode'=>'101022',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }


    public function account($param)
    {
        $head=[
            'serCode'=>'101015',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }
    public function shareParAccount($param) {
        $head=[
            'serCode'=>'101024',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }
    public function findAccount($param) {
        $head=[
            'serCode'=>'101016',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }
    public function settlement($param) {
        $head=[
            'serCode'=>'101019',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }
    public function transfer($param)
    {
        $head=[
            'serCode'=>'201005',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapayTransfer($data);
    }

    public function requestHnapayTransfer($param) {
        if(isset($this->config['mode'])&&$this->config['mode']=='normal'){
            $url="https://uwebpay.hnapay.com/webpay/unifiedAPI.htm";//正式
        }else{
            $url="https://uwebpaytest.hnapay.com/webpay/unifiedAPI.htm";//测试
        }
        //$msg= urlencode(base64_encode(json_encode($param)));
        $msg= base64_encode(json_encode($param,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
        $return = Http::post($url,['msg'=>$msg]);
        $return=json_decode($return,1);
        if(!isset($return['msg'])){
            return $return;
        }
        return json_decode(base64_decode($return['msg']),1);
    }

    public function find($param) {
        $head=[
            'serCode'=>'101007',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }

    /**
     * 支付单报关
     */
    public function reportPay($param){
        $head=[
            'serCode'=>'101017',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }

    /**
     * 空中分账
     */
    public function ledgerAccount($param){
        $head=[
            'serCode'=>'101026',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }

    /**
     * 分账查询
     */
    public function checkLedger($param){
        $head=[
            'serCode'=>'101028',//服务代码
            'merCode'=> $this->config['merCode'],//商户代码
            'orderId'=>(string)time().rand(100,999),//请求流水号交易唯一标识
            'merDate'=>date('Ymd'),//商户订单日期
            'merTime'=>date('His'),//商户订单时间
            'versionNo'=>'2.0',
            'signType'=>'2'
        ];
        $data['head']=$head;
        $data['content']=$param;
        $data['sign']=$this->makeSign($data);
        return $this->requestHnapay($data);
    }


    public function requestHnapay($param) {
        if(isset($this->config['mode'])&&$this->config['mode']=='normal'){
            $url="https://uwebgate.hnapay.com/webgate/unifiedAPI.htm";//正式
        }else{
            $url="https://uwebgatetest.hnapay.com/webgate/unifiedAPI.htm";//测试
        }
        //$msg= urlencode(base64_encode(json_encode($param)));
        $msg= base64_encode(json_encode($param,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
//        $Request=new Request;
//        $return = $Request->httpRequest($url,'post',['msg'=>$msg]);
        $return=Http::post($url,['msg'=>$msg]);
        $return=json_decode($return,1);
        if(!isset($return['msg'])){
            return $return;
        }
        return json_decode(base64_decode($return['msg']),1);
    }

    /**
     * 签名
     */
    public function makeSign($array=[])
    {
        $headcont= json_encode($array,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
        $merchantPubKey=$this->config['merchantPubKey'];
        $signMsg= md5(md5($headcont).$merchantPubKey);
        return $signMsg;
    }

    public static  function getClientIp($type = 0)
    {
        $type       =  $type ? 1 : 0;
        static $ip  =   NULL;
        if ($ip !== NULL) return $ip[$type];

        if (isset($_SERVER['HTTP_X_REAL_IP'])) {//nginx 代理模式下，获取客户端真实IP
            $ip = $_SERVER['HTTP_X_REAL_IP'];
        } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {//客户端的ip
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {//浏览当前页面的用户计算机的网关
            $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $pos    =   array_search('unknown',$arr);
            if(false !== $pos) unset($arr[$pos]);
            $ip     =   trim($arr[0]);
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip     =   $_SERVER['REMOTE_ADDR'];//浏览当前页面的用户计算机的ip地址
        } else {
            $ip = '121.199.39.16';
        }
        // IP地址合法验证
        $long = sprintf("%u",ip2long($ip));
        $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
        return $ip[$type];
    }

}